/* Pointer manipulation routines.
 *
 * Copyright (c) 1993-2007 Leo Spiekman, Xaveer Leijtens
 *
 * This file is part of libMask.
 *
 * libMask is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free
 * Software Foundation, either version 3 of the License, or (at your
 * option) any later version.
 *
 * libMask is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
 * for more details.
 *
 * You should have received a copy of the GNU General Public License along
 * with libMask.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "mask.h"

struct pointer pstack[STACK_DEPTH];  /* Pointer stack */
struct pointer *pstackp=NULL;        /* Pointer stack pointer */
struct pointer cp;                   /* Current generating position */

void makeabs(struct pointer *ptr, struct pointer org)
{
  double x, y;
  int f;

  f = (org.flip == FLIP) ? -1 : 1;
  x = org.x + ptr->x * cos(org.a) - f * ptr->y * sin(org.a);
  y = org.y + ptr->x * sin(org.a) + f * ptr->y * cos(org.a);
  ptr->x = x;
  ptr->y = y;
  ptr->a = map_0_2pi(f * ptr->a + org.a);
  ptr->flip = ((ptr->flip == FLIP) ^ (org.flip == FLIP)) ? FLIP : NOFLIP;
}

void makerel(struct pointer *ptr, struct pointer org)
{
  double x, y;
  int f;

  f = (org.flip == FLIP) ? -1 : 1;
  x = (ptr->x - org.x) * cos(org.a) + (ptr->y - org.y) * sin(org.a);
  y = -f * (ptr->x - org.x) * sin(org.a) + f * (ptr->y - org.y) * cos(org.a);
  ptr->x = x;
  ptr->y = y;
  ptr->a = map_0_2pi(f * (ptr->a - org.a));
  ptr->flip = ((ptr->flip == FLIP) ^ (org.flip == FLIP)) ? FLIP : NOFLIP;
}

void init_cp()
{
  cp.x = 0.0;
  cp.y = 0.0;
  cp.a = 0.0;
  cp.flip = NOFLIP;
}

void init_pstack()
{
  init_cp();
  pstackp = pstack;
  *pstackp = cp;
}

void push_cp()
{
  if (pstackp - pstack == STACK_DEPTH - 1) {
    fprintf(stderr, "push_cp: pointer stack overflow\n");
    exit(1);
  }
  *++pstackp = cp;
}

void pop_cp()
{
  if (pstackp == pstack) {
    fprintf(stderr, "pop_cp: pointer stack underflow\n");
    exit(1);
  }
  cp = *pstackp--;
}

void drop()
{
  if (pstackp == pstack) {
    fprintf(stderr, "drop: pointer stack underflow\n");
    exit(1);
  }
  pstackp--;
}

void org(double x, double y, double a, int flip)
{
  cp.x = x;
  cp.y = y;
  cp.a = a;
  cp.flip = flip;

  makeabs(&cp, *pstackp);
}

void move(double x, double y, double a, int flip)
{
  push_cp();
  org(x, y, a, flip);
  drop();
}

void skip(double l)
{
  move(l,0.0,0.0,NOFLIP);
}

void offset(double d)
{
  move(0.0,-d,0.0,NOFLIP);
}

void rotate(double a)
{
  move(0.0,0.0,-a,NOFLIP);
}

void movept(double l, double w, int p1, int p2)
{
  if ((p1 < 1) || (p1 > 9)) {
    fprintf(stderr, "movept: starting point invalid: %d\n", p1);
    exit(1);
  }
  if ((p2 < 1) || (p2 > 9)) {
    fprintf(stderr, "movept: ending point invalid: %d\n", p2);
    exit(1);
  }

  move(l * ((p2 - 1) % 3 - (p1 - 1) % 3) / 2,
    w * ((p2 - 1) / 3 - (p1 - 1) / 3) / 2, 0.0, NOFLIP);
}

void print_pstack()
{
  struct pointer *ptmp;        /* Pointer stack pointer */
  int i = 0;
  fprintf(stderr, "pointer stack:\n");
  for (ptmp = pstackp; ptmp != pstack; ptmp--) {
    fprintf(stderr, "%2d: x=%g um, y=%g um, a=%g deg\n",
      ++i, (*ptmp).x*1e6, (*ptmp).y*1e6, DEG((*ptmp).a));
  }
}

void print_abscp()
{
  fprintf(stderr, "abscp (um): (%9.3f,%9.3f), angle %8.5f%s\n",
    cp.x*1e6, cp.y*1e6, cp.a, ((cp.flip == FLIP) ? ", flipped" : ""));
}

void print_relcp()
{
  struct pointer tmpcp;

  tmpcp = cp;
  makerel(&tmpcp, *pstackp);
  fprintf(stderr, "relcp (um): (%9.3f,%9.3f), angle %8.5f%s\n",
    tmpcp.x*1e6, tmpcp.y*1e6, tmpcp.a, (tmpcp.flip ? ", flipped" : ""));
}
